Package org.python.compiler

Source Code of org.python.compiler.CodeCompiler$ExceptionHandler

// Copyright (c) Corporation for National Research Initiatives

package org.python.compiler;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Stack;
import java.util.Vector;

import org.python.core.CompilerFlags;
import org.python.core.PyComplex;
import org.python.core.PyFloat;
import org.python.core.PyInteger;
import org.python.core.PyLong;
import org.python.core.PyObject;
import org.python.parser.ParseException;
import org.python.parser.SimpleNode;
import org.python.parser.Visitor;
import org.python.parser.ast.Assert;
import org.python.parser.ast.Assign;
import org.python.parser.ast.Attribute;
import org.python.parser.ast.AugAssign;
import org.python.parser.ast.BinOp;
import org.python.parser.ast.BoolOp;
import org.python.parser.ast.Break;
import org.python.parser.ast.Call;
import org.python.parser.ast.ClassDef;
import org.python.parser.ast.Compare;
import org.python.parser.ast.Continue;
import org.python.parser.ast.Delete;
import org.python.parser.ast.Dict;
import org.python.parser.ast.Ellipsis;
import org.python.parser.ast.Exec;
import org.python.parser.ast.Expr;
import org.python.parser.ast.Expression;
import org.python.parser.ast.ExtSlice;
import org.python.parser.ast.For;
import org.python.parser.ast.FunctionDef;
import org.python.parser.ast.Global;
import org.python.parser.ast.If;
import org.python.parser.ast.Import;
import org.python.parser.ast.ImportFrom;
import org.python.parser.ast.Index;
import org.python.parser.ast.Interactive;
import org.python.parser.ast.Lambda;
import org.python.parser.ast.List;
import org.python.parser.ast.ListComp;
import org.python.parser.ast.Name;
import org.python.parser.ast.Num;
import org.python.parser.ast.Pass;
import org.python.parser.ast.Print;
import org.python.parser.ast.Raise;
import org.python.parser.ast.Repr;
import org.python.parser.ast.Return;
import org.python.parser.ast.Slice;
import org.python.parser.ast.Str;
import org.python.parser.ast.Subscript;
import org.python.parser.ast.Suite;
import org.python.parser.ast.TryExcept;
import org.python.parser.ast.TryFinally;
import org.python.parser.ast.Tuple;
import org.python.parser.ast.UnaryOp;
import org.python.parser.ast.Unicode;
import org.python.parser.ast.While;
import org.python.parser.ast.Yield;
import org.python.parser.ast.excepthandlerType;
import org.python.parser.ast.exprType;
import org.python.parser.ast.expr_contextType;
import org.python.parser.ast.keywordType;
import org.python.parser.ast.listcompType;
import org.python.parser.ast.modType;
import org.python.parser.ast.stmtType;

public class CodeCompiler extends Visitor implements ClassConstants //, PythonGrammarTreeConstants
{

    public static final Object Exit = new Integer(1);
    public static final Object NoExit = null;

    public static final int GET = 0;
    public static final int SET = 1;
    public static final int DEL = 2;
    public static final int AUGGET = 3;
    public static final int AUGSET = 4;

    public Module module;
    public Code code;
    public ConstantPool pool;
    public CodeCompiler mrefs;
    public CompilerFlags cflags;

    int temporary;
    int augmode;
    int augtmp1;
    int augtmp2;
    int augtmp3;
    int augtmp4;

    public boolean fast_locals, print_results;

    public Hashtable tbl;
    public ScopeInfo my_scope;

    boolean optimizeGlobals = true;
    public Vector names;
    public String className;

    public Stack continueLabels, breakLabels;
    public Stack exceptionHandlers;
    public Vector yields = new Vector();

    /* break/continue finally's level.
     * This is the lowest level in the exceptionHandlers which should
     * be executed at break or continue.
     * It is saved/updated/restored when compiling loops.
     * A similar level for returns is not needed because a new CodeCompiler
     * is used for each PyCode, ie. each 'function'.
     * When returning through finally's all the exceptionHandlers are executed.
     */
    public int bcfLevel = 0;

    public CodeCompiler(Module module, boolean print_results) {
        this.module = module;
        this.print_results = print_results;

        mrefs = this;
        pool = module.classfile.pool;

        continueLabels = new Stack();
        breakLabels = new Stack();
        exceptionHandlers = new Stack();
    }

    public int PyNone;

    public void getNone() throws IOException {
        if (mrefs.PyNone == 0) {
            mrefs.PyNone = pool.Fieldref("org/python/core/Py", "None", $pyObj);
        }
        code.getstatic(mrefs.PyNone);
    }

    public void loadFrame() throws Exception {
        code.aload(1);
    }

    int f_lasti;

    public void setLastI(int idx) throws Exception {
        if (mrefs.f_lasti == 0) {
            mrefs.f_lasti = code.pool.Fieldref("org/python/core/PyFrame", "f_lasti", "I");
        }
        loadFrame();
        code.iconst(idx);
        code.putfield(mrefs.f_lasti);
    }

    int f_back;

    private void loadf_back() throws Exception {
        if (mrefs.f_back == 0) {
            mrefs.f_back = code.pool.Fieldref("org/python/core/PyFrame", "f_back", $pyFrame);
        }
        code.getfield(f_back);
    }

    public int storeTop() throws Exception {
        int tmp = code.getLocal("org/python/core/PyObject");
        code.astore(tmp);
        return tmp;
    }

    public int setline;

    public void setline(int line) throws Exception {
        //System.out.println("line: "+line+", "+code.stack);
        if (module.linenumbers) {
            code.setline(line);
            loadFrame();
            code.iconst(line);
            if (mrefs.setline == 0) {
                mrefs.setline = pool.Methodref("org/python/core/PyFrame", "setline", "(I)V");
            }
            code.invokevirtual(mrefs.setline);
        }
    }

    public void setline(SimpleNode node) throws Exception {
        setline(node.beginLine);
    }

    public void set(SimpleNode node) throws Exception {
        int tmp = storeTop();
        set(node, tmp);
        code.aconst_null();
        code.astore(tmp);
        code.freeLocal(tmp);
    }

    boolean inSet = false;

    public void set(SimpleNode node, int tmp) throws Exception {
        //System.out.println("tmp: "+tmp);
        if (inSet) {
            System.out.println("recurse set: " + tmp + ", " + temporary);
        }
        temporary = tmp;
        visit(node);
    }

    private void saveAugTmps(SimpleNode node, int count) throws Exception {
        if (count >= 4) {
            augtmp4 = code.getLocal("org/python/core/PyObject");
            code.astore(augtmp4);
        }
        if (count >= 3) {
            augtmp3 = code.getLocal("org/python/core/PyObject");
            code.astore(augtmp3);
        }
        if (count >= 2) {
            augtmp2 = code.getLocal("org/python/core/PyObject");
            code.astore(augtmp2);
        }
        augtmp1 = code.getLocal("org/python/core/PyObject");
        code.astore(augtmp1);

        code.aload(augtmp1);
        if (count >= 2)
            code.aload(augtmp2);
        if (count >= 3)
            code.aload(augtmp3);
        if (count >= 4)
            code.aload(augtmp4);
    }

    private void restoreAugTmps(SimpleNode node, int count) throws Exception {
        code.aload(augtmp1);
        code.freeLocal(augtmp1);
        if (count == 1)
            return;
        code.aload(augtmp2);
        code.freeLocal(augtmp2);
        if (count == 2)
            return;
        code.aload(augtmp3);
        code.freeLocal(augtmp3);
        if (count == 3)
            return;
        code.aload(augtmp4);
        code.freeLocal(augtmp4);
    }

    public void parse(modType node, Code code, boolean fast_locals, String className, boolean classBody,
            ScopeInfo scope, CompilerFlags cflags) throws Exception {
        this.fast_locals = fast_locals;
        this.className = className;
        this.code = code;
        this.cflags = cflags;

        my_scope = scope;
        names = scope.names;

        tbl = scope.tbl;
        optimizeGlobals = fast_locals && !scope.exec && !scope.from_import_star;

        Object exit = visit(node);
        //System.out.println("exit: "+exit+", "+(exit==null));

        if (classBody) {
            loadFrame();
            code.invokevirtual("org/python/core/PyFrame", "getf_locals", "()" + $pyObj);
            code.areturn();
        } else {
            if (exit == null) {
                //System.out.println("no exit");
                setLastI(-1);

                getNone();
                code.areturn();
            }
        }
    }

    public Object visitInteractive(Interactive node) throws Exception {
        traverse(node);
        return null;
    }

    public Object visitModule(org.python.parser.ast.Module suite) throws Exception {
        if (mrefs.setglobal == 0) {
            mrefs.setglobal = code.pool.Methodref("org/python/core/PyFrame", "setglobal", "(" + $str + $pyObj + ")V");
        }

        if (suite.body.length > 0 && suite.body[0] instanceof Expr && ((Expr) suite.body[0]).value instanceof Str) {
            loadFrame();
            code.ldc("__doc__");
            visit(((Expr) suite.body[0]).value);
            code.invokevirtual(mrefs.setglobal);
        }
        if (module.setFile) {
            loadFrame();
            code.ldc("__file__");
            module.filename.get(code);
            code.invokevirtual(mrefs.setglobal);
        }
        traverse(suite);
        return null;
    }

    public Object visitExpression(Expression node) throws Exception {
        if (my_scope.generator && node.body != null) {
            module.error("'return' with argument inside generator", true, node);
        }
        return visitReturn(new Return(node.body, node), true);
    }

    public int EmptyObjects;

    public void makeArray(SimpleNode[] nodes) throws Exception {
        int n;

        if (nodes == null)
            n = 0;
        else
            n = nodes.length;

        if (n == 0) {
            if (mrefs.EmptyObjects == 0) {
                mrefs.EmptyObjects = code.pool.Fieldref("org/python/core/Py", "EmptyObjects", $pyObjArr);
            }
            code.getstatic(mrefs.EmptyObjects);
        } else {
            int tmp = code.getLocal("[org/python/core/PyObject");
            code.iconst(n);
            code.anewarray(code.pool.Class("org/python/core/PyObject"));
            code.astore(tmp);

            for (int i = 0; i < n; i++) {
                code.aload(tmp);
                code.iconst(i);
                visit(nodes[i]);
                code.aastore();
            }
            code.aload(tmp);
            code.freeLocal(tmp);
        }
    }

    public void getDocString(stmtType[] suite) throws Exception {
        //System.out.println("doc: "+suite.getChild(0));
        if (suite.length > 0 && suite[0] instanceof Expr && ((Expr) suite[0]).value instanceof Str) {
            visit(((Expr) suite[0]).value);
        } else {
            code.aconst_null();
        }
    }

    int getclosure;

    public boolean makeClosure(ScopeInfo scope) throws Exception {
        if (scope == null || scope.freevars == null)
            return false;
        int n = scope.freevars.size();
        if (n == 0)
            return false;

        if (mrefs.getclosure == 0) {
            mrefs.getclosure = code.pool.Methodref("org/python/core/PyFrame", "getclosure", "(I)" + $pyObj);
        }

        int tmp = code.getLocal("[org/python/core/PyObject");
        code.iconst(n);
        code.anewarray(code.pool.Class("org/python/core/PyObject"));
        code.astore(tmp);
        Hashtable upTbl = scope.up.tbl;
        for (int i = 0; i < n; i++) {
            code.aload(tmp);
            code.iconst(i);
            loadFrame();
            for (int j = 1; j < scope.distance; j++) {
                loadf_back();
            }
            SymInfo symInfo = (SymInfo) upTbl.get(scope.freevars.elementAt(i));
            code.iconst(symInfo.env_index);
            code.invokevirtual(getclosure);
            code.aastore();
        }

        code.aload(tmp);
        code.freeLocal(tmp);

        return true;
    }

    int f_globals, PyFunction_init, PyFunction_closure_init;

    public Object visitFunctionDef(FunctionDef node) throws Exception {
        String name = getName(node.name);

        setline(node);

        code.new_(code.pool.Class("org/python/core/PyFunction"));
        code.dup();
        loadFrame();
        if (mrefs.f_globals == 0) {
            mrefs.f_globals = code.pool.Fieldref("org/python/core/PyFrame", "f_globals", $pyObj);
        }
        code.getfield(mrefs.f_globals);

        ScopeInfo scope = module.getScopeInfo(node);

        makeArray(scope.ac.getDefaults());

        scope.setup_closure();
        scope.dump();
        module.PyCode(new Suite(node.body, node), name, true, className, false, false, node.beginLine, scope, cflags)
                .get(code);

        getDocString(node.body);

        if (!makeClosure(scope)) {
            if (mrefs.PyFunction_init == 0) {
                mrefs.PyFunction_init = code.pool.Methodref("org/python/core/PyFunction", "<init>", "(" + $pyObj
                        + $pyObjArr + $pyCode + $pyObj + ")V");
            }
            code.invokespecial(mrefs.PyFunction_init);
        } else {
            if (mrefs.PyFunction_closure_init == 0) {
                mrefs.PyFunction_closure_init = code.pool.Methodref("org/python/core/PyFunction", "<init>", "("
                        + $pyObj + $pyObjArr + $pyCode + $pyObj + $pyObjArr + ")V");
            }
            code.invokespecial(mrefs.PyFunction_closure_init);

        }

        set(new Name(node.name, Name.Store, node));
        return null;
    }

    public int printResult;

    public Object visitExpr(Expr node) throws Exception {
        setline(node);
        visit(node.value);

        if (print_results) {
            if (mrefs.printResult == 0) {
                mrefs.printResult = code.pool.Methodref("org/python/core/Py", "printResult", "(" + $pyObj + ")V");
            }
            code.invokestatic(mrefs.printResult);
        } else {
            code.pop();
        }
        return null;
    }

    public Object visitAssign(Assign node) throws Exception {
        setline(node);
        visit(node.value);
        if (node.targets.length == 1) {
            set(node.targets[0]);
            return null;
        }
        int tmp = storeTop();
        for (int i = node.targets.length - 1; i >= 0; i--) {
            set(node.targets[i], tmp);
        }
        code.freeLocal(tmp);
        return null;
    }

    public int print1, print2, print3, print4, print5, print6;

    public Object visitPrint(Print node) throws Exception {
        setline(node);
        int tmp = -1;
        int printcomma, printlnv, println;

        if (node.dest != null) {
            visit(node.dest);
            tmp = storeTop();
            if (mrefs.print4 == 0) {
                mrefs.print4 = pool.Methodref("org/python/core/Py", "printComma", "(" + $pyObj + $pyObj + ")V");
            }
            printcomma = mrefs.print4;
            if (mrefs.print5 == 0) {
                mrefs.print5 = pool.Methodref("org/python/core/Py", "println", "(" + $pyObj + $pyObj + ")V");
            }
            println = mrefs.print5;
            if (mrefs.print6 == 0) {
                mrefs.print6 = pool.Methodref("org/python/core/Py", "printlnv", "(" + $pyObj + ")V");
            }
            printlnv = mrefs.print6;
        } else {
            if (mrefs.print1 == 0) {
                mrefs.print1 = pool.Methodref("org/python/core/Py", "printComma", "(" + $pyObj + ")V");
            }
            printcomma = mrefs.print1;
            if (mrefs.print2 == 0) {
                mrefs.print2 = pool.Methodref("org/python/core/Py", "println", "(" + $pyObj + ")V");
            }
            println = mrefs.print2;
            if (mrefs.print3 == 0) {
                mrefs.print3 = pool.Methodref("org/python/core/Py", "println", "()V");
            }
            printlnv = mrefs.print3;
        }

        if (node.values == null || node.values.length == 0) {
            if (node.dest != null)
                code.aload(tmp);
            code.invokestatic(printlnv);
        } else {
            for (int i = 0; i < node.values.length; i++) {
                if (node.dest != null)
                    code.aload(tmp);
                visit(node.values[i]);
                if (node.nl && i == node.values.length - 1) {
                    code.invokestatic(println);
                } else {
                    code.invokestatic(printcomma);
                }
            }
        }
        if (node.dest != null)
            code.freeLocal(tmp);
        return null;
    }

    public Object visitDelete(Delete node) throws Exception {
        setline(node);
        traverse(node);
        return null;
    }

    public Object visitPass(Pass node) throws Exception {
        setline(node);
        return null;
    }

    public Object visitBreak(Break node) throws Exception {
        //setline(node); Not needed here...
        if (breakLabels.empty()) {
            throw new ParseException("'break' outside loop", node);
        }

        doFinallysDownTo(bcfLevel);

        code.goto_((Label) breakLabels.peek());
        return null;
    }

    public Object visitContinue(Continue node) throws Exception {
        //setline(node); Not needed here...
        if (continueLabels.empty()) {
            throw new ParseException("'continue' not properly in loop", node);
        }

        doFinallysDownTo(bcfLevel);

        code.goto_((Label) continueLabels.peek());
        return Exit;
    }

    int yield_count = 0;

    int f_savedlocals;

    public Object visitYield(Yield node) throws Exception {
        setline(node);
        if (!fast_locals) {
            throw new ParseException("'yield' outside function", node);
        }

        if (inFinallyBody()) {
            throw new ParseException("'yield' not allowed in a 'try' " + "block with a 'finally' clause", node);
        }

        saveLocals();
        visit(node.value);
        setLastI(++yield_count);
        code.areturn();

        Label restart = code.getLabel();
        yields.addElement(restart);
        restart.setPosition();
        restoreLocals();
        return null;
    }

    private boolean inFinallyBody() {
        for (int i = 0; i < exceptionHandlers.size(); ++i) {
            ExceptionHandler handler = (ExceptionHandler) exceptionHandlers.elementAt(i);
            if (handler.isFinallyHandler()) {
                return true;
            }
        }
        return false;
    }

    private void restoreLocals() throws Exception {
        endExceptionHandlers();

        Vector v = code.getActiveLocals();

        loadFrame();
        if (mrefs.f_savedlocals == 0) {
            mrefs.f_savedlocals = code.pool.Fieldref("org/python/core/PyFrame", "f_savedlocals", "[Ljava/lang/Object;");
        }
        code.getfield(mrefs.f_savedlocals);

        int locals = code.getLocal("[java/lang/Object");
        code.astore(locals);

        for (int i = 0; i < v.size(); i++) {
            String type = (String) v.elementAt(i);
            if (type == null)
                continue;
            code.aload(locals);
            code.iconst(i);
            code.aaload();
            code.checkcast(code.pool.Class(type));
            code.astore(i);
        }
        code.freeLocal(locals);

        restartExceptionHandlers();
    }

    /**
     *  Close all the open exception handler ranges.  This should be paired
     *  with restartExceptionHandlers to delimit internal code that
     *  shouldn't be handled by user handlers.  This allows us to set
     *  variables without the verifier thinking we might jump out of our
     *  handling with an exception.
     */
    private void endExceptionHandlers() {
        Label end = code.getLabelAtPosition();
        for (int i = 0; i < exceptionHandlers.size(); ++i) {
            ExceptionHandler handler = (ExceptionHandler) exceptionHandlers.elementAt(i);
            handler.exceptionEnds.addElement(end);
        }
    }

    private void restartExceptionHandlers() {
        Label start = code.getLabelAtPosition();
        for (int i = 0; i < exceptionHandlers.size(); ++i) {
            ExceptionHandler handler = (ExceptionHandler) exceptionHandlers.elementAt(i);
            handler.exceptionStarts.addElement(start);
        }
    }

    private void saveLocals() throws Exception {
        Vector v = code.getActiveLocals();
        //System.out.println("bs:" + bs);
        code.iconst(v.size());
        //code.anewarray(code.pool.Class("org/python/core/PyObject"));
        code.anewarray(code.pool.Class("java/lang/Object"));
        int locals = code.getLocal("[java/lang/Object");
        code.astore(locals);

        for (int i = 0; i < v.size(); i++) {
            String type = (String) v.elementAt(i);
            if (type == null)
                continue;
            code.aload(locals);
            code.iconst(i);
            //code.checkcast(code.pool.Class("java/lang/Object"));
            if (i == 2222) {
                code.aconst_null();
            } else
                code.aload(i);
            code.aastore();
        }

        if (mrefs.f_savedlocals == 0) {
            mrefs.f_savedlocals = code.pool.Fieldref("org/python/core/PyFrame", "f_savedlocals", "[Ljava/lang/Object;");
        }

        loadFrame();
        code.aload(locals);
        code.putfield(mrefs.f_savedlocals);
        code.freeLocal(locals);
    }

    public Object visitReturn(Return node) throws Exception {
        return visitReturn(node, false);
    }

    public Object visitReturn(Return node, boolean inEval) throws Exception {
        setline(node);
        if (!inEval && !fast_locals) {
            throw new ParseException("'return' outside function", node);
        }
        int tmp = 0;
        if (node.value != null) {
            if (my_scope.generator)
                throw new ParseException("'return' with argument " + "inside generator", node);
            visit(node.value);
            tmp = code.getReturnLocal();
            code.astore(tmp);
        }
        doFinallysDownTo(0);

        setLastI(-1);

        if (node.value != null) {
            code.aload(tmp);
        } else {
            getNone();
        }
        code.areturn();
        return Exit;
    }

    public int makeException0, makeException1, makeException2, makeException3;

    public Object visitRaise(Raise node) throws Exception {
        setline(node);
        traverse(node);
        if (node.type == null) {
            if (mrefs.makeException0 == 0) {
                mrefs.makeException0 = code.pool.Methodref("org/python/core/Py", "makeException", "()" + $pyExc);
            }
            code.invokestatic(mrefs.makeException0);
        } else if (node.inst == null) {
            if (mrefs.makeException1 == 0) {
                mrefs.makeException1 = code.pool.Methodref("org/python/core/Py", "makeException", "(" + $pyObj + ")"
                        + $pyExc);
            }
            code.invokestatic(mrefs.makeException1);
        } else if (node.tback == null) {
            if (mrefs.makeException2 == 0) {
                mrefs.makeException2 = code.pool.Methodref("org/python/core/Py", "makeException", "(" + $pyObj + $pyObj
                        + ")" + $pyExc);
            }
            code.invokestatic(mrefs.makeException2);
        } else {
            if (mrefs.makeException3 == 0) {
                mrefs.makeException3 = code.pool.Methodref("org/python/core/Py", "makeException", "(" + $pyObj + $pyObj
                        + $pyObj + ")" + $pyExc);
            }
            code.invokestatic(mrefs.makeException3);
        }
        code.athrow();
        return Exit;
    }

    public int importOne, importOneAs;

    public Object visitImport(Import node) throws Exception {
        setline(node);
        for (int i = 0; i < node.names.length; i++) {
            String asname = null;
            if (node.names[i].asname != null) {
                String name = node.names[i].name;
                asname = node.names[i].asname;
                code.ldc(name);
                loadFrame();
                if (mrefs.importOneAs == 0) {
                    mrefs.importOneAs = code.pool.Methodref("org/python/core/imp", "importOneAs", "(" + $str + $pyFrame
                            + ")" + $pyObj);
                }
                code.invokestatic(mrefs.importOneAs);
            } else {
                String name = node.names[i].name;
                asname = name;
                if (asname.indexOf('.') > 0)
                    asname = asname.substring(0, asname.indexOf('.'));
                code.ldc(name);
                loadFrame();
                if (mrefs.importOne == 0) {
                    mrefs.importOne = code.pool.Methodref("org/python/core/imp", "importOne", "(" + $str + $pyFrame
                            + ")" + $pyObj);
                }
                code.invokestatic(mrefs.importOne);
            }
            set(new Name(asname, Name.Store, node));
        }
        return null;
    }

    public int importAll, importFrom;

    public Object visitImportFrom(ImportFrom node) throws Exception {
        Future.checkFromFuture(node); // future stmt support
        setline(node);
        code.ldc(node.module);
        if (node.names.length > 0) {
            String[] names = new String[node.names.length];
            String[] asnames = new String[node.names.length];
            for (int i = 0; i < node.names.length; i++) {
                names[i] = node.names[i].name;
                asnames[i] = node.names[i].asname;
                if (asnames[i] == null)
                    asnames[i] = names[i];
            }
            makeStrings(code, names, names.length);

            loadFrame();
            if (mrefs.importFrom == 0) {
                mrefs.importFrom = code.pool.Methodref("org/python/core/imp", "importFrom", "(" + $str + $strArr
                        + $pyFrame + ")" + $pyObjArr);
            }
            code.invokestatic(mrefs.importFrom);
            int tmp = storeTop();
            for (int i = 0; i < node.names.length; i++) {
                code.aload(tmp);
                code.iconst(i);
                code.aaload();
                set(new Name(asnames[i], Name.Store, node));
            }
            code.freeLocal(tmp);
        } else {
            loadFrame();
            if (mrefs.importAll == 0) {
                mrefs.importAll = code.pool.Methodref("org/python/core/imp", "importAll", "(" + $str + $pyFrame + ")V");
            }
            code.invokestatic(mrefs.importAll);
        }
        return null;
    }

    public Object visitGlobal(Global node) throws Exception {
        return null;
    }

    public int exec;

    public Object visitExec(Exec node) throws Exception {
        setline(node);
        visit(node.body);

        if (node.globals != null) {
            visit(node.globals);
        } else {
            code.aconst_null();
        }

        if (node.locals != null) {
            visit(node.locals);
        } else {
            code.aconst_null();
        }

        //do the real work here
        if (mrefs.exec == 0) {
            mrefs.exec = code.pool.Methodref("org/python/core/Py", "exec", "(" + $pyObj + $pyObj + $pyObj + ")V");
        }
        code.invokestatic(mrefs.exec);
        return null;
    }

    public int asserttype;

    public Object visitAssert(Assert node) throws Exception {
        setline(node);
        Label end_of_assert = code.getLabel();

        /* First do an if __debug__: */
        loadFrame();
        emitGetGlobal("__debug__");

        if (mrefs.nonzero == 0) {
            mrefs.nonzero = code.pool.Methodref("org/python/core/PyObject", "__nonzero__", "()Z");
        }
        code.invokevirtual(mrefs.nonzero);

        code.ifeq(end_of_assert);

        /* Now do the body of the assert. If PyObject.__nonzero__ is true,
        then the assertion succeeded, the message portion should not be
        processed. Otherwise, the message will be processed. */
        visit(node.test);
        code.invokevirtual(mrefs.nonzero);

        /* If evaluation is false, then branch to end of method */
        code.ifne(end_of_assert);

        /* Push exception type onto stack(Py.AssertionError) */
        if (mrefs.asserttype == 0) {
            mrefs.asserttype = code.pool.Fieldref("org/python/core/Py", "AssertionError", "Lorg/python/core/PyObject;");
        }

        code.getstatic(mrefs.asserttype);

        /* Visit the message part of the assertion, or pass Py.None */
        if (node.msg != null) {
            visit(node.msg);
        } else {
            getNone();
        }

        if (mrefs.makeException2 == 0) {
            mrefs.makeException2 = code.pool.Methodref("org/python/core/Py", "makeException", "(" + $pyObj + $pyObj
                    + ")" + $pyExc);
        }
        code.invokestatic(mrefs.makeException2);

        /* Raise assertion error. Only executes this logic if assertion
           failed */
        code.athrow();

        /* And finally set the label for the end of it all */
        end_of_assert.setPosition();

        return null;
    }

    public int nonzero;

    public Object doTest(Label end_of_if, If node, int index) throws Exception {
        Label end_of_suite = code.getLabel();

        setline(node.test);
        visit(node.test);
        if (mrefs.nonzero == 0) {
            mrefs.nonzero = code.pool.Methodref("org/python/core/PyObject", "__nonzero__", "()Z");
        }
        code.invokevirtual(mrefs.nonzero);
        code.ifeq(end_of_suite);

        Object exit = suite(node.body);

        if (end_of_if != null && exit == null)
            code.goto_(end_of_if);

        end_of_suite.setPosition();

        if (node.orelse != null) {
            return suite(node.orelse) != null ? exit : null;
        } else {
            return null;
        }
    }

    public Object visitIf(If node) throws Exception {
        Label end_of_if = null;
        if (node.orelse != null)
            end_of_if = code.getLabel();

        Object exit = doTest(end_of_if, node, 0);
        if (end_of_if != null)
            end_of_if.setPosition();
        return exit;
    }

    public int beginLoop() {
        continueLabels.push(code.getLabel());
        breakLabels.push(code.getLabel());
        int savebcf = bcfLevel;
        bcfLevel = exceptionHandlers.size();
        return savebcf;
    }

    public void finishLoop(int savebcf) {
        continueLabels.pop();
        breakLabels.pop();
        bcfLevel = savebcf;
    }

    public Object visitWhile(While node) throws Exception {
        int savebcf = beginLoop();
        Label continue_loop = (Label) continueLabels.peek();
        Label break_loop = (Label) breakLabels.peek();

        Label start_loop = code.getLabel();

        code.goto_(continue_loop);
        start_loop.setPosition();

        //Do suite
        suite(node.body);

        continue_loop.setPosition();
        setline(node);

        //Do test
        visit(node.test);
        if (mrefs.nonzero == 0) {
            mrefs.nonzero = code.pool.Methodref("org/python/core/PyObject", "__nonzero__", "()Z");
        }
        code.invokevirtual(mrefs.nonzero);
        code.ifne(start_loop);

        finishLoop(savebcf);

        if (node.orelse != null) {
            //Do else
            suite(node.orelse);
        }
        break_loop.setPosition();

        // Probably need to detect "guaranteed exits"
        return null;
    }

    public int iter = 0;
    public int iternext = 0;

    public Object visitFor(For node) throws Exception {
        int savebcf = beginLoop();
        Label continue_loop = (Label) continueLabels.peek();
        Label break_loop = (Label) breakLabels.peek();
        Label start_loop = code.getLabel();
        Label next_loop = code.getLabel();

        int iter_tmp = code.getLocal("org/python/core/PyObject");
        int expr_tmp = code.getLocal("org/python/core/PyObject");

        setline(node);

        //parse the list
        visit(node.iter);

        //set up the loop iterator
        if (mrefs.iter == 0) {
            mrefs.iter = code.pool.Methodref("org/python/core/PyObject", "__iter__", "()" + $pyObj);
        }
        code.invokevirtual(mrefs.iter);
        code.astore(iter_tmp);

        //do check at end of loop.  Saves one opcode ;-)
        code.goto_(next_loop);

        start_loop.setPosition();
        //set iter variable to current entry in list
        set(node.target, expr_tmp);

        //evaluate for body
        suite(node.body);

        continue_loop.setPosition();

        next_loop.setPosition();
        setline(node);
        //get the next element from the list
        code.aload(iter_tmp);
        if (mrefs.iternext == 0) {
            mrefs.iternext = code.pool.Methodref("org/python/core/PyObject", "__iternext__", "()" + $pyObj);
        }
        code.invokevirtual(mrefs.iternext);
        code.astore(expr_tmp);
        code.aload(expr_tmp);
        //if no more elements then fall through
        code.ifnonnull(start_loop);

        finishLoop(savebcf);

        if (node.orelse != null) {
            //Do else clause if provided
            suite(node.orelse);
        }

        break_loop.setPosition();

        code.freeLocal(iter_tmp);
        code.freeLocal(expr_tmp);

        // Probably need to detect "guaranteed exits"
        return null;
    }

    public int match_exception;

    public void exceptionTest(int exc, Label end_of_exceptions, TryExcept node, int index) throws Exception {
        for (int i = 0; i < node.handlers.length; i++) {
            excepthandlerType handler = node.handlers[i];

            //setline(name);
            Label end_of_self = code.getLabel();

            if (handler.type != null) {
                code.aload(exc);
                //get specific exception
                visit(handler.type);
                if (mrefs.match_exception == 0) {
                    mrefs.match_exception = code.pool.Methodref("org/python/core/Py", "matchException", "(" + $pyExc
                            + $pyObj + ")Z");
                }
                code.invokestatic(mrefs.match_exception);
                code.ifeq(end_of_self);
            } else {
                if (i != node.handlers.length - 1) {
                    throw new ParseException("bare except must be last except clause", handler.type);
                }
            }

            if (handler.name != null) {
                code.aload(exc);
                code.getfield(code.pool.Fieldref("org/python/core/PyException", "value", "Lorg/python/core/PyObject;"));
                set(handler.name);
            }

            //do exception body
            suite(handler.body);
            code.goto_(end_of_exceptions);
            end_of_self.setPosition();
        }
        code.aload(exc);
        code.athrow();
    }

    public int add_traceback;

    public Object visitTryFinally(TryFinally node) throws Exception {
        Label start = code.getLabel();
        Label end = code.getLabel();
        Label handlerStart = code.getLabel();
        Label finallyEnd = code.getLabel();

        Object ret;

        ExceptionHandler inFinally = new ExceptionHandler(node);

        // Do protected suite
        exceptionHandlers.push(inFinally);

        int excLocal = code.getLocal("java/lang/Throwable");
        code.aconst_null();
        code.astore(excLocal);

        start.setPosition();
        inFinally.exceptionStarts.addElement(start);

        ret = suite(node.body);

        end.setPosition();
        inFinally.exceptionEnds.addElement(end);
        inFinally.bodyDone = true;

        exceptionHandlers.pop();

        if (ret == NoExit) {
            inlineFinally(inFinally);
            code.goto_(finallyEnd);
        }

        // Handle any exceptions that get thrown in suite
        handlerStart.setPosition();
        code.stack = 1;
        code.astore(excLocal);

        code.aload(excLocal);
        loadFrame();

        if (mrefs.add_traceback == 0) {
            mrefs.add_traceback = code.pool.Methodref("org/python/core/Py", "addTraceback", "(" + $throwable + $pyFrame
                    + ")V");
        }
        code.invokestatic(mrefs.add_traceback);

        inlineFinally(inFinally);
        code.aload(excLocal);
        code.checkcast(code.pool.Class("java/lang/Throwable"));
        code.athrow();

        finallyEnd.setPosition();

        code.freeLocal(excLocal);

        inFinally.addExceptionHandlers(handlerStart);
        // According to any JVM verifiers, this code block might not return
        return null;
    }

    private void inlineFinally(ExceptionHandler handler) throws Exception {
        if (!handler.bodyDone) {
            // end the previous exception block so inlined finally code doesn't
            // get covered by our exception handler.
            handler.exceptionEnds.addElement(code.getLabelAtPosition());
            // also exiting the try: portion of this particular finally
        }
        if (handler.isFinallyHandler()) {
            suite(handler.node.finalbody);
        }
    }

    private void reenterProtectedBody(ExceptionHandler handler) throws Exception {
        // restart exception coverage
        handler.exceptionStarts.addElement(code.getLabelAtPosition());
    }

    /**
     *  Inline the finally handling code for levels down to the levelth parent
     *  (0 means all).  This takes care to avoid having more nested finallys
     *  catch exceptions throw by the parent finally code.  This also pops off
     *  all the handlers above level temporarily.
     */
    private void doFinallysDownTo(int level) throws Exception {
        Stack poppedHandlers = new Stack();
        while (exceptionHandlers.size() > level) {
            ExceptionHandler handler = (ExceptionHandler) exceptionHandlers.pop();
            inlineFinally(handler);
            poppedHandlers.push(handler);
        }
        while (poppedHandlers.size() > 0) {
            ExceptionHandler handler = (ExceptionHandler) poppedHandlers.pop();
            reenterProtectedBody(handler);
            exceptionHandlers.push(handler);
        }
    }

    public int set_exception;

    public Object visitTryExcept(TryExcept node) throws Exception {
        Label start = code.getLabel();
        Label end = code.getLabel();
        Label handler_start = code.getLabel();
        Label handler_end = code.getLabel();
        ExceptionHandler handler = new ExceptionHandler();

        start.setPosition();
        handler.exceptionStarts.addElement(start);
        exceptionHandlers.push(handler);
        //Do suite
        Object exit = suite(node.body);
        //System.out.println("exit: "+exit+", "+(exit != null));
        exceptionHandlers.pop();
        end.setPosition();
        handler.exceptionEnds.addElement(end);

        if (exit == null)
            code.goto_(handler_end);

        handler_start.setPosition();
        //Stack has eactly one item at start of handler
        code.stack = 1;

        loadFrame();

        if (mrefs.set_exception == 0) {
            mrefs.set_exception = code.pool.Methodref("org/python/core/Py", "setException", "(" + $throwable + $pyFrame
                    + ")" + $pyExc);
        }
        code.invokestatic(mrefs.set_exception);

        int exc = code.getFinallyLocal("java/lang/Throwable");
        code.astore(exc);

        if (node.orelse == null) {
            //No else clause to worry about
            exceptionTest(exc, handler_end, node, 1);
            handler_end.setPosition();
        } else {
            //Have else clause
            Label else_end = code.getLabel();
            exceptionTest(exc, else_end, node, 1);
            handler_end.setPosition();

            //do else clause
            suite(node.orelse);
            else_end.setPosition();
        }

        code.freeFinallyLocal(exc);
        handler.addExceptionHandlers(handler_start);
        return null;
    }

    public Object visitSuite(Suite node) throws Exception {
        return suite(node.body);
    }

    public Object suite(stmtType[] stmts) throws Exception {
        int n = stmts.length;
        for (int i = 0; i < n; i++) {
            Object exit = visit(stmts[i]);
            //System.out.println("exit: "+exit+", "+n+", "+(exit != null));
            if (exit != null)
                return Exit;
        }
        return null;
    }

    public Object visitBoolOp(BoolOp node) throws Exception {
        Label end = code.getLabel();
        visit(node.values[0]);
        for (int i = 1; i < node.values.length; i++) {
            code.dup();
            if (mrefs.nonzero == 0) {
                mrefs.nonzero = code.pool.Methodref("org/python/core/PyObject", "__nonzero__", "()Z");
            }
            code.invokevirtual(mrefs.nonzero);
            switch (node.op) {
                case BoolOp.Or:
                    code.ifne(end);
                    break;
                case BoolOp.And:
                    code.ifeq(end);
                    break;
            }
            code.pop();
            visit(node.values[i]);
        }
        end.setPosition();
        return null;
    }

    public Object visitCompare(Compare node) throws Exception {
        int tmp1 = code.getLocal("org/python/core/PyObject");
        int tmp2 = code.getLocal("org/python/core/PyObject");
        int op;

        if (mrefs.nonzero == 0) {
            mrefs.nonzero = code.pool.Methodref("org/python/core/PyObject", "__nonzero__", "()Z");
        }

        Label end = code.getLabel();

        visit(node.left);

        int n = node.ops.length;
        for (int i = 0; i < n - 1; i++) {
            visit(node.comparators[i]);
            code.dup();
            code.astore(tmp1);
            code.invokevirtual(make_cmpop(node.ops[i]));
            code.dup();
            code.astore(tmp2);
            code.invokevirtual(mrefs.nonzero);
            code.ifeq(end);
            code.aload(tmp1);
        }

        visit(node.comparators[n - 1]);
        code.invokevirtual(make_cmpop(node.ops[n - 1]));

        if (n > 1) {
            code.astore(tmp2);
            end.setPosition();
            code.aload(tmp2);
        }
        code.freeLocal(tmp1);
        code.freeLocal(tmp2);
        return null;
    }

    int[] compare_ops = new int[11];

    public int make_cmpop(int op) throws Exception {
        if (compare_ops[op] == 0) {
            String name = null;
            switch (op) {
                case Compare.Eq:
                    name = "_eq";
                    break;
                case Compare.NotEq:
                    name = "_ne";
                    break;
                case Compare.Lt:
                    name = "_lt";
                    break;
                case Compare.LtE:
                    name = "_le";
                    break;
                case Compare.Gt:
                    name = "_gt";
                    break;
                case Compare.GtE:
                    name = "_ge";
                    break;
                case Compare.Is:
                    name = "_is";
                    break;
                case Compare.IsNot:
                    name = "_isnot";
                    break;
                case Compare.In:
                    name = "_in";
                    break;
                case Compare.NotIn:
                    name = "_notin";
                    break;
            }
            compare_ops[op] = code.pool.Methodref("org/python/core/PyObject", name, "(" + $pyObj + ")" + $pyObj);
        }
        return compare_ops[op];
    }

    static String[] bin_methods = new String[] { null, "_add", "_sub", "_mul", "_div", "_mod", "_pow", "_lshift",
            "_rshift", "_or", "_xor", "_and", "_floordiv", };

    int[] bin_ops = new int[13];

    public int make_binop(int op) throws Exception {
        if (bin_ops[op] == 0) {
            String name = bin_methods[op];
            if (op == BinOp.Div && module.getFutures().areDivisionOn()) {
                name = "_truediv";
            }
            bin_ops[op] = code.pool.Methodref("org/python/core/PyObject", name, "(" + $pyObj + ")" + $pyObj);
        }
        return bin_ops[op];
    }

    public Object visitBinOp(BinOp node) throws Exception {
        visit(node.left);
        visit(node.right);
        code.invokevirtual(make_binop(node.op));
        return null;
    }

    static String[] unary_methods = new String[] { null, "__invert__", "__not__", "__pos__", "__neg__", };

    int[] unary_ops = new int[unary_methods.length];

    public int make_unaryop(int op) throws Exception {
        if (unary_ops[op] == 0) {
            String name = unary_methods[op];
            unary_ops[op] = code.pool.Methodref("org/python/core/PyObject", name, "()" + $pyObj);
        }
        return unary_ops[op];
    }

    public Object visitUnaryOp(UnaryOp node) throws Exception {
        visit(node.operand);
        code.invokevirtual(make_unaryop(node.op));
        return null;
    }

    static String[] aug_methods = new String[] { null, "__iadd__", "__isub__", "__imul__", "__idiv__", "__imod__",
            "__ipow__", "__ilshift__", "__irshift__", "__ior__", "__ixor__", "__iand__", "__ifloordiv__", };

    int[] augbin_ops = new int[aug_methods.length];

    public int make_augbinop(int op) throws Exception {
        if (augbin_ops[op] == 0) {
            String name = aug_methods[op];
            if (op == BinOp.Div && module.getFutures().areDivisionOn()) {
                name = "__itruediv__";
            }
            augbin_ops[op] = code.pool.Methodref("org/python/core/PyObject", name, "(" + $pyObj + ")" + $pyObj);
        }
        return augbin_ops[op];
    }

    public Object visitAugAssign(AugAssign node) throws Exception {
        visit(node.value);
        int tmp = storeTop();

        augmode = expr_contextType.Load;
        visit(node.target);

        code.aload(tmp);
        code.invokevirtual(make_augbinop(node.op));
        code.freeLocal(tmp);

        temporary = storeTop();
        augmode = expr_contextType.Store;
        visit(node.target);
        code.freeLocal(temporary);

        return null;
    }

    public static void makeStrings(Code c, String[] names, int n) throws IOException {
        c.iconst(n);
        c.anewarray(c.pool.Class("java/lang/String"));
        int strings = c.getLocal("[java/lang/String");
        c.astore(strings);
        for (int i = 0; i < n; i++) {
            c.aload(strings);
            c.iconst(i);
            c.ldc(names[i]);
            c.aastore();
        }
        c.aload(strings);
        c.freeLocal(strings);
    }

    public int invokea0, invokea1, invokea2;
    public int invoke2;

    public Object Invoke(Attribute node, SimpleNode[] values) throws Exception {
        String name = getName(node.attr);
        visit(node.value);
        code.ldc(name);

        //System.out.println("invoke: "+name+": "+values.length);

        switch (values.length) {
            case 0:
                if (mrefs.invokea0 == 0) {
                    mrefs.invokea0 = code.pool.Methodref("org/python/core/PyObject", "invoke", "(" + $str + ")"
                            + $pyObj);
                }
                code.invokevirtual(mrefs.invokea0);
                break;
            case 1:
                if (mrefs.invokea1 == 0) {
                    mrefs.invokea1 = code.pool.Methodref("org/python/core/PyObject", "invoke", "(" + $str + $pyObj
                            + ")" + $pyObj);
                }
                visit(values[0]);
                code.invokevirtual(mrefs.invokea1);
                break;
            case 2:
                if (mrefs.invokea2 == 0) {
                    mrefs.invokea2 = code.pool.Methodref("org/python/core/PyObject", "invoke", "(" + $str + $pyObj
                            + $pyObj + ")" + $pyObj);
                }
                visit(values[0]);
                visit(values[1]);
                code.invokevirtual(mrefs.invokea2);
                break;
            default:
                makeArray(values);
                if (mrefs.invoke2 == 0) {
                    mrefs.invoke2 = code.pool.Methodref("org/python/core/PyObject", "invoke", "(" + $str + $pyObjArr
                            + ")" + $pyObj);
                }
                code.invokevirtual(mrefs.invoke2);
                break;
        }

        return null;
    }

    public int callextra;
    public int call1, call2;
    public int calla0, calla1, calla2, calla3, calla4;

    public Object visitCall(Call node) throws Exception {
        String[] keys = new String[node.keywords.length];
        exprType[] values = new exprType[node.args.length + keys.length];
        for (int i = 0; i < node.args.length; i++) {
            values[i] = node.args[i];
        }
        for (int i = 0; i < node.keywords.length; i++) {
            keys[i] = node.keywords[i].arg;
            values[node.args.length + i] = node.keywords[i].value;
        }

        // Detect a method invocation with no keywords
        if ((node.keywords == null || node.keywords.length == 0) && node.starargs == null && node.kwargs == null
                && node.func instanceof Attribute) {
            return Invoke((Attribute) node.func, values);
        }

        visit(node.func);

        if (node.starargs != null || node.kwargs != null) {
            makeArray(values);
            makeStrings(code, keys, keys.length);
            if (node.starargs == null)
                code.aconst_null();
            else
                visit(node.starargs);
            if (node.kwargs == null)
                code.aconst_null();
            else
                visit(node.kwargs);

            if (mrefs.callextra == 0) {
                mrefs.callextra = code.pool.Methodref("org/python/core/PyObject", "_callextra", "(" + $pyObjArr
                        + $strArr + $pyObj + $pyObj + ")" + $pyObj);
            }
            code.invokevirtual(mrefs.callextra);
        } else if (keys.length > 0) {
            makeArray(values);
            makeStrings(code, keys, keys.length);

            if (mrefs.call1 == 0) {
                mrefs.call1 = code.pool.Methodref("org/python/core/PyObject", "__call__", "(" + $pyObjArr + $strArr
                        + ")" + $pyObj);
            }
            code.invokevirtual(mrefs.call1);
        } else {
            switch (values.length) {
                case 0:
                    if (mrefs.calla0 == 0) {
                        mrefs.calla0 = code.pool.Methodref("org/python/core/PyObject", "__call__", "()" + $pyObj);
                    }
                    code.invokevirtual(mrefs.calla0);
                    break;
                case 1:
                    if (mrefs.calla1 == 0) {
                        mrefs.calla1 = code.pool.Methodref("org/python/core/PyObject", "__call__", "(" + $pyObj + ")"
                                + $pyObj);
                    }
                    visit(values[0]);
                    code.invokevirtual(mrefs.calla1);
                    break;
                case 2:
                    if (mrefs.calla2 == 0) {
                        mrefs.calla2 = code.pool.Methodref("org/python/core/PyObject", "__call__", "(" + $pyObj
                                + $pyObj + ")" + $pyObj);
                    }
                    visit(values[0]);
                    visit(values[1]);
                    code.invokevirtual(mrefs.calla2);
                    break;
                case 3:
                    if (mrefs.calla3 == 0) {
                        mrefs.calla3 = code.pool.Methodref("org/python/core/PyObject", "__call__", "(" + $pyObj
                                + $pyObj + $pyObj + ")" + $pyObj);
                    }
                    visit(values[0]);
                    visit(values[1]);
                    visit(values[2]);
                    code.invokevirtual(mrefs.calla3);
                    break;
                case 4:
                    if (mrefs.calla4 == 0) {
                        mrefs.calla4 = code.pool.Methodref("org/python/core/PyObject", "__call__", "(" + $pyObj
                                + $pyObj + $pyObj + $pyObj + ")" + $pyObj);
                    }
                    visit(values[0]);
                    visit(values[1]);
                    visit(values[2]);
                    visit(values[3]);
                    code.invokevirtual(mrefs.calla4);
                    break;
                default:
                    makeArray(values);
                    if (mrefs.call2 == 0) {
                        mrefs.call2 = code.pool.Methodref("org/python/core/PyObject", "__call__", "(" + $pyObjArr + ")"
                                + $pyObj);
                    }
                    code.invokevirtual(mrefs.call2);
                    break;
            }
        }
        return null;
    }

    public int getslice, setslice, delslice;

    public Object Slice(Subscript node, Slice slice) throws Exception {
        int ctx = node.ctx;
        if (ctx == node.AugStore && augmode == node.Store) {
            restoreAugTmps(node, 4);
            ctx = node.Store;
        } else {
            visit(node.value);
            if (slice.lower != null)
                visit(slice.lower);
            else
                code.aconst_null();
            if (slice.upper != null)
                visit(slice.upper);
            else
                code.aconst_null();
            if (slice.step != null)
                visit(slice.step);
            else
                code.aconst_null();

            if (node.ctx == node.AugStore && augmode == node.Load) {
                saveAugTmps(node, 4);
                ctx = node.Load;
            }
        }

        switch (ctx) {
            case Subscript.Del:
                if (mrefs.delslice == 0) {
                    mrefs.delslice = code.pool.Methodref("org/python/core/PyObject", "__delslice__", "(" + $pyObj
                            + $pyObj + $pyObj + ")V");
                }
                code.invokevirtual(mrefs.delslice);
                return null;
            case Subscript.Load:
                if (mrefs.getslice == 0) {
                    mrefs.getslice = code.pool.Methodref("org/python/core/PyObject", "__getslice__", "(" + $pyObj
                            + $pyObj + $pyObj + ")" + $pyObj);
                }
                code.invokevirtual(mrefs.getslice);
                return null;
            case Subscript.Store:
                code.aload(temporary);
                if (mrefs.setslice == 0) {
                    mrefs.setslice = code.pool.Methodref("org/python/core/PyObject", "__setslice__", "(" + $pyObj
                            + $pyObj + $pyObj + $pyObj + ")V");
                }
                code.invokevirtual(mrefs.setslice);
                return null;
        }
        return null;

    }

    public int getitem, delitem, setitem;

    public Object visitSubscript(Subscript node) throws Exception {
        if (node.slice instanceof Slice) {
            return Slice(node, (Slice) node.slice);
        }

        int ctx = node.ctx;
        if (node.ctx == node.AugStore && augmode == node.Store) {
            restoreAugTmps(node, 2);
            ctx = node.Store;
        } else {
            visit(node.value);
            visit(node.slice);

            if (node.ctx == node.AugStore && augmode == node.Load) {
                saveAugTmps(node, 2);
                ctx = node.Load;
            }
        }

        switch (ctx) {
            case Subscript.Del:
                if (mrefs.delitem == 0) {
                    mrefs.delitem = code.pool.Methodref("org/python/core/PyObject", "__delitem__", "(" + $pyObj + ")V");
                }
                code.invokevirtual(mrefs.delitem);
                return null;
            case Subscript.Load:
                if (mrefs.getitem == 0) {
                    mrefs.getitem = code.pool.Methodref("org/python/core/PyObject", "__getitem__", "(" + $pyObj + ")"
                            + $pyObj);
                }
                code.invokevirtual(mrefs.getitem);
                return null;
            case Subscript.Store:
                code.aload(temporary);
                if (mrefs.setitem == 0) {
                    mrefs.setitem = code.pool.Methodref("org/python/core/PyObject", "__setitem__", "(" + $pyObj
                            + $pyObj + ")V");
                }
                code.invokevirtual(mrefs.setitem);
                return null;
        }
        return null;
    }

    public Object visitIndex(Index node) throws Exception {
        traverse(node);
        return null;
    }

    public Object visitExtSlice(ExtSlice node) throws Exception {
        code.new_(code.pool.Class("org/python/core/PyTuple"));
        code.dup();
        makeArray(node.dims);
        if (mrefs.PyTuple_init == 0) {
            mrefs.PyTuple_init = code.pool.Methodref("org/python/core/PyTuple", "<init>", "(" + $pyObjArr + ")V");
        }
        code.invokespecial(mrefs.PyTuple_init);
        return null;
    }

    public int getattr, delattr, setattr;

    public Object visitAttribute(Attribute node) throws Exception {

        int ctx = node.ctx;
        if (node.ctx == node.AugStore && augmode == node.Store) {
            restoreAugTmps(node, 2);
            ctx = node.Store;
        } else {
            visit(node.value);
            code.ldc(getName(node.attr));

            if (node.ctx == node.AugStore && augmode == node.Load) {
                saveAugTmps(node, 2);
                ctx = node.Load;
            }
        }

        switch (ctx) {
            case Attribute.Del:
                if (mrefs.delattr == 0) {
                    mrefs.delattr = code.pool.Methodref("org/python/core/PyObject", "__delattr__", "(" + $str + ")V");
                }
                code.invokevirtual(mrefs.delattr);
                return null;
            case Attribute.Load:
                if (mrefs.getattr == 0) {
                    mrefs.getattr = code.pool.Methodref("org/python/core/PyObject", "__getattr__", "(" + $str + ")"
                            + $pyObj);
                }
                code.invokevirtual(mrefs.getattr);
                return null;
            case Attribute.Store:
                code.aload(temporary);
                if (mrefs.setattr == 0) {
                    mrefs.setattr = code.pool.Methodref("org/python/core/PyObject", "__setattr__", "(" + $str + $pyObj
                            + ")V");
                }
                code.invokevirtual(mrefs.setattr);
                return null;
        }
        return null;
    }

    public int getitem2, unpackSequence;

    public Object seqSet(exprType[] nodes) throws Exception {
        if (mrefs.unpackSequence == 0) {
            mrefs.unpackSequence = code.pool.Methodref("org/python/core/Py", "unpackSequence", "(" + $pyObj + "I)"
                    + $pyObjArr);
        }

        code.aload(temporary);
        code.iconst(nodes.length);
        code.invokestatic(mrefs.unpackSequence);

        int tmp = code.getLocal("[org/python/core/PyObject");
        code.astore(tmp);

        for (int i = 0; i < nodes.length; i++) {
            code.aload(tmp);
            code.iconst(i);
            code.aaload();
            set(nodes[i]);
        }
        code.freeLocal(tmp);

        return null;
    }

    public Object seqDel(exprType[] nodes) throws Exception {
        for (int i = 0; i < nodes.length; i++) {
            visit(nodes[i]);
        }
        return null;
    }

    public int PyTuple_init, PyList_init, PyDictionary_init;

    public Object visitTuple(Tuple node) throws Exception {
        /* if (mode ==AUGSET)
            throw new ParseException(
                      "augmented assign to tuple not possible", node); */
        if (node.ctx == node.Store)
            return seqSet(node.elts);
        if (node.ctx == node.Del)
            return seqDel(node.elts);

        code.new_(code.pool.Class("org/python/core/PyTuple"));
        code.dup();
        makeArray(node.elts);
        if (mrefs.PyTuple_init == 0) {
            mrefs.PyTuple_init = code.pool.Methodref("org/python/core/PyTuple", "<init>", "(" + $pyObjArr + ")V");
        }
        code.invokespecial(mrefs.PyTuple_init);
        return null;
    }

    /*
        public Object fplist(SimpleNode node) throws Exception {
            if (mode == SET) return seqSet(node);
            throw new ParseException("in fplist node", node);
        }
    */

    public Object visitList(List node) throws Exception {
        /* if (mode ==AUGSET)
            throw new ParseException(
                      "augmented assign to list not possible", node); */

        if (node.ctx == node.Store)
            return seqSet(node.elts);
        if (node.ctx == node.Del)
            return seqDel(node.elts);

        code.new_(code.pool.Class("org/python/core/PyList"));
        code.dup();
        makeArray(node.elts);
        if (mrefs.PyList_init == 0) {
            mrefs.PyList_init = code.pool.Methodref("org/python/core/PyList", "<init>", "(" + $pyObjArr + ")V");
        }
        code.invokespecial(mrefs.PyList_init);
        return null;
    }

    int list_comprehension_count = 0;

    public int PyList_init2;

    public Object visitListComp(ListComp node) throws Exception {
        code.new_(code.pool.Class("org/python/core/PyList"));
        code.dup();
        if (mrefs.PyList_init2 == 0) {
            mrefs.PyList_init2 = code.pool.Methodref("org/python/core/PyList", "<init>", "()V");
        }
        code.invokespecial(mrefs.PyList_init2);

        code.dup();

        code.ldc("append");

        if (mrefs.getattr == 0) {
            mrefs.getattr = code.pool.Methodref("org/python/core/PyObject", "__getattr__", "(" + $str + ")" + $pyObj);
        }
        code.invokevirtual(mrefs.getattr);

        String tmp_append = "_[" + (++list_comprehension_count) + "]";

        set(new Name(tmp_append, Name.Store, node));

        stmtType n = new Expr(new Call(new Name(tmp_append, Name.Load, node), new exprType[] { node.elt },
                new keywordType[0], null, null, node), node);

        for (int i = node.generators.length - 1; i >= 0; i--) {
            listcompType lc = node.generators[i];
            for (int j = lc.ifs.length - 1; j >= 0; j--) {
                n = new If(lc.ifs[j], new stmtType[] { n }, null, lc.ifs[j]);
            }
            n = new For(lc.target, lc.iter, new stmtType[] { n }, null, lc);
        }
        visit(n);
        visit(new Delete(new exprType[] { new Name(tmp_append, Name.Del) }));

        return null;
    }

    public Object visitDict(Dict node) throws Exception {
        code.new_(code.pool.Class("org/python/core/PyDictionary"));
        code.dup();
        SimpleNode[] elts = new SimpleNode[node.keys.length * 2];
        for (int i = 0; i < node.keys.length; i++) {
            elts[i * 2] = node.keys[i];
            elts[i * 2 + 1] = node.values[i];
        }
        makeArray(elts);
        if (mrefs.PyDictionary_init == 0) {
            mrefs.PyDictionary_init = code.pool.Methodref("org/python/core/PyDictionary", "<init>", "(" + $pyObjArr
                    + ")V");
        }
        code.invokespecial(mrefs.PyDictionary_init);
        return null;
    }

    public Object visitRepr(Repr node) throws Exception {
        visit(node.value);
        code.invokevirtual("org/python/core/PyObject", "__repr__", "()" + $pyStr);
        return null;
    }

    public int PyFunction_init1, PyFunction_closure_init1;

    public Object visitLambda(Lambda node) throws Exception {
        String name = "<lambda>";

        //Add a return node onto the outside of suite;
        modType retSuite = new Suite(new stmtType[] { new Return(node.body, node) }, node);

        setline(node);

        code.new_(code.pool.Class("org/python/core/PyFunction"));
        code.dup();
        loadFrame();
        if (mrefs.f_globals == 0) {
            mrefs.f_globals = code.pool.Fieldref("org/python/core/PyFrame", "f_globals", $pyObj);
        }
        code.getfield(mrefs.f_globals);

        ScopeInfo scope = module.getScopeInfo(node);

        makeArray(scope.ac.getDefaults());

        scope.setup_closure();
        scope.dump();
        module.PyCode(retSuite, name, true, className, false, false, node.beginLine, scope, cflags).get(code);

        if (!makeClosure(scope)) {
            if (mrefs.PyFunction_init1 == 0) {
                mrefs.PyFunction_init1 = code.pool.Methodref("org/python/core/PyFunction", "<init>", "(" + $pyObj
                        + $pyObjArr + $pyCode + ")V");
            }
            code.invokespecial(mrefs.PyFunction_init1);
        } else {
            if (mrefs.PyFunction_closure_init1 == 0) {
                mrefs.PyFunction_closure_init1 = code.pool.Methodref("org/python/core/PyFunction", "<init>", "("
                        + $pyObj + $pyObjArr + $pyCode + $pyObjArr + ")V");
            }
            code.invokespecial(mrefs.PyFunction_closure_init1);
        }

        return null;
    }

    public int Ellipsis;

    public Object visitEllipsis(Ellipsis node) throws Exception {
        if (mrefs.Ellipsis == 0) {
            mrefs.Ellipsis = code.pool.Fieldref("org/python/core/Py", "Ellipsis", "Lorg/python/core/PyObject;");
        }
        code.getstatic(mrefs.Ellipsis);
        return null;
    }

    public int PySlice_init;

    public Object visitSlice(Slice node) throws Exception {
        code.new_(code.pool.Class("org/python/core/PySlice"));
        code.dup();
        if (node.lower == null)
            getNone();
        else
            visit(node.lower);
        if (node.upper == null)
            getNone();
        else
            visit(node.upper);
        if (node.step == null)
            getNone();
        else
            visit(node.step);
        if (mrefs.PySlice_init == 0) {
            mrefs.PySlice_init = code.pool.Methodref("org/python/core/PySlice", "<init>", "(" + $pyObj + $pyObj
                    + $pyObj + ")V");
        }
        code.invokespecial(mrefs.PySlice_init);
        return null;
    }

    public int makeClass, makeClass_closure;

    public Object visitClassDef(ClassDef node) throws Exception {
        setline(node);

        //Get class name
        String name = getName(node.name);
        //System.out.println("name: "+name);
        code.ldc(name);

        makeArray(node.bases);

        ScopeInfo scope = module.getScopeInfo(node);

        scope.setup_closure();
        scope.dump();
        //Make code object out of suite
        module.PyCode(new Suite(node.body, node), name, false, name, true, false, node.beginLine, scope, cflags).get(
                code);

        //Get doc string (if there)
        getDocString(node.body);

        //Make class out of name, bases, and code
        if (!makeClosure(scope)) {
            if (mrefs.makeClass == 0) {
                mrefs.makeClass = code.pool.Methodref("org/python/core/Py", "makeClass", "(" + $str + $pyObjArr
                        + $pyCode + $pyObj + ")" + $pyObj);
            }
            code.invokestatic(mrefs.makeClass);
        } else {
            if (mrefs.makeClass_closure == 0) {
                mrefs.makeClass_closure = code.pool.Methodref("org/python/core/Py", "makeClass", "(" + $str + $pyObjArr
                        + $pyCode + $pyObj + $pyObjArr + ")" + $pyObj);
            }
            code.invokestatic(mrefs.makeClass_closure);
        }

        //Assign this new class to the given name
        set(new Name(node.name, Name.Store, node));
        return null;
    }

    public Object visitNum(Num node) throws Exception {
        if (node.n instanceof PyInteger) {
            module.PyInteger(((PyInteger) node.n).getValue()).get(code);
        } else if (node.n instanceof PyLong) {
            module.PyLong(((PyObject) node.n).__str__().toString()).get(code);
        } else if (node.n instanceof PyFloat) {
            module.PyFloat(((PyFloat) node.n).getValue()).get(code);
        } else if (node.n instanceof PyComplex) {
            module.PyComplex(((PyComplex) node.n).imag).get(code);
        }
        return null;
    }

    private String getName(String name) {
        if (className != null && name.startsWith("__") && !name.endsWith("__")) {
            //remove leading '_' from classname
            int i = 0;
            while (className.charAt(i) == '_')
                i++;
            return "_" + className.substring(i) + name;
        }
        return name;
    }

    int getglobal, getlocal1, getlocal2;
    int setglobal, setlocal1, setlocal2;
    int delglobal, dellocal1, dellocal2;
    int getderef, setderef;

    void emitGetGlobal(String name) throws Exception {
        code.ldc(name);
        if (mrefs.getglobal == 0) {
            mrefs.getglobal = code.pool.Methodref("org/python/core/PyFrame", "getglobal", "(" + $str + ")" + $pyObj);
        }
        code.invokevirtual(mrefs.getglobal);
    }

    public Object visitName(Name node) throws Exception {
        String name;
        if (fast_locals)
            name = node.id;
        else
            name = getName(node.id);

        SymInfo syminf = (SymInfo) tbl.get(name);

        int ctx = node.ctx;
        if (ctx == node.AugStore) {
            ctx = augmode;
        }

        switch (ctx) {
            case Name.Load:
                loadFrame();
                if (syminf != null) {
                    int flags = syminf.flags;
                    if ((flags & ScopeInfo.GLOBAL) != 0 || optimizeGlobals
                            && (flags & (ScopeInfo.BOUND | ScopeInfo.CELL | ScopeInfo.FREE)) == 0) {
                        emitGetGlobal(name);
                        return null;
                    }
                    if (fast_locals) {
                        if ((flags & ScopeInfo.CELL) != 0) {
                            code.iconst(syminf.env_index);
                            if (mrefs.getderef == 0) {
                                mrefs.getderef = code.pool.Methodref("org/python/core/PyFrame", "getderef", "(I)"
                                        + $pyObj);
                            }
                            code.invokevirtual(mrefs.getderef);
                            return null;
                        }
                        if ((flags & ScopeInfo.BOUND) != 0) {
                            code.iconst(syminf.locals_index);
                            if (mrefs.getlocal2 == 0) {
                                mrefs.getlocal2 = code.pool.Methodref("org/python/core/PyFrame", "getlocal", "(I)"
                                        + $pyObj);
                            }
                            code.invokevirtual(mrefs.getlocal2);
                            return null;
                        }
                    }
                    if ((flags & ScopeInfo.FREE) != 0 && (flags & ScopeInfo.BOUND) == 0) {
                        code.iconst(syminf.env_index);
                        if (mrefs.getderef == 0) {
                            mrefs.getderef = code.pool.Methodref("org/python/core/PyFrame", "getderef", "(I)" + $pyObj);
                        }
                        code.invokevirtual(mrefs.getderef);
                        return null;
                    }
                }
                code.ldc(name);
                if (mrefs.getlocal1 == 0) {
                    mrefs.getlocal1 = code.pool.Methodref("org/python/core/PyFrame", "getname", "(" + $str + ")"
                            + $pyObj);
                }
                code.invokevirtual(mrefs.getlocal1);
                return null;

            case Name.Store:
                loadFrame();
                if (syminf != null && (syminf.flags & ScopeInfo.GLOBAL) != 0) {
                    code.ldc(name);
                    code.aload(temporary);
                    if (mrefs.setglobal == 0) {
                        mrefs.setglobal = code.pool.Methodref("org/python/core/PyFrame", "setglobal", "(" + $str
                                + $pyObj + ")V");
                    }
                    code.invokevirtual(mrefs.setglobal);
                } else {
                    if (!fast_locals) {
                        code.ldc(name);
                        code.aload(temporary);
                        if (mrefs.setlocal1 == 0) {
                            mrefs.setlocal1 = code.pool.Methodref("org/python/core/PyFrame", "setlocal", "(" + $str
                                    + $pyObj + ")V");
                        }
                        code.invokevirtual(mrefs.setlocal1);
                    } else {
                        if (syminf == null) {
                            System.err.println("internal compiler error: " + node);
                        }
                        if ((syminf.flags & ScopeInfo.CELL) != 0) {
                            code.iconst(syminf.env_index);
                            code.aload(temporary);
                            if (mrefs.setderef == 0) {
                                mrefs.setderef = code.pool.Methodref("org/python/core/PyFrame", "setderef", "(I"
                                        + $pyObj + ")V");
                            }
                            code.invokevirtual(mrefs.setderef);
                        } else {
                            code.iconst(syminf.locals_index);
                            code.aload(temporary);
                            if (mrefs.setlocal2 == 0) {
                                mrefs.setlocal2 = code.pool.Methodref("org/python/core/PyFrame", "setlocal", "(I"
                                        + $pyObj + ")V");
                            }
                            code.invokevirtual(mrefs.setlocal2);
                        }
                    }
                }
                return null;
            case Name.Del: {
                loadFrame();
                if (syminf != null && (syminf.flags & ScopeInfo.GLOBAL) != 0) {
                    code.ldc(name);
                    if (mrefs.delglobal == 0) {
                        mrefs.delglobal = code.pool
                                .Methodref("org/python/core/PyFrame", "delglobal", "(" + $str + ")V");
                    }
                    code.invokevirtual(mrefs.delglobal);
                } else {
                    if (!fast_locals) {
                        code.ldc(name);
                        if (mrefs.dellocal1 == 0) {
                            mrefs.dellocal1 = code.pool.Methodref("org/python/core/PyFrame", "dellocal", "(" + $str
                                    + ")V");
                        }
                        code.invokevirtual(mrefs.dellocal1);
                    } else {
                        if (syminf == null) {
                            System.err.println("internal compiler error: " + node);
                        }
                        if ((syminf.flags & ScopeInfo.CELL) != 0) {
                            module.error("can not delete variable '" + name + "' referenced in nested scope", true,
                                    node);
                        }
                        code.iconst(syminf.locals_index);
                        if (mrefs.dellocal2 == 0) {
                            mrefs.dellocal2 = code.pool.Methodref("org/python/core/PyFrame", "dellocal", "(I)V");
                        }
                        code.invokevirtual(mrefs.dellocal2);
                    }
                }
                return null;
            }
        }
        return null;
    }

    public Object visitUnicode(Unicode node) throws Exception {
        String s = node.s;
        if (s.length() > 32767) {
            throw new ParseException("string constant too large (more than 32767 characters)", node);
        }
        module.PyUnicode(s).get(code);
        return null;
    }

    public Object visitStr(Str node) throws Exception {
        String s = node.s;
        if (s.length() > 32767) {
            throw new ParseException("string constant too large (more than 32767 characters)", node);
        }
        module.PyString(s).get(code);
        return null;
    }

    protected Object unhandled_node(SimpleNode node) throws Exception {
        throw new Exception("Unhandled node " + node);
    }

    /**
     *  Data about a given exception range whether a try:finally: or a
     *  try:except:.  The finally needs to inline the finally block for
     *  each exit of the try: section, so we carry around that data for it.
     * 
     *  Both of these need to stop exception coverage of an area that is either
     *  the inlined finally of a parent try:finally: or the reentry block after
     *  a yield.  Thus we keep around a set of exception ranges that the
     *  catch block will eventually handle.
     */
    class ExceptionHandler {
        /**
         *  Each handler gets several exception ranges, this is because inlined
         *  finally exit code shouldn't be covered by the exception handler of
         *  that finally block.  Thus each time we inline the finally code, we
         *  stop one range and then enter a new one.
         *
         *  We also need to stop coverage for the recovery of the locals after
         *  a yield.
         */
        public Vector exceptionStarts = new Vector();
        public Vector exceptionEnds = new Vector();

        public boolean bodyDone = false;

        public TryFinally node = null;

        public ExceptionHandler() {
        }

        public ExceptionHandler(TryFinally n) {
            node = n;
        }

        public boolean isFinallyHandler() {
            return node != null;
        }

        public void addExceptionHandlers(Label handlerStart) throws Exception {
            int throwable = code.pool.Class("java/lang/Throwable");
            for (int i = 0; i < exceptionStarts.size(); ++i) {
                Label start = (Label) exceptionStarts.elementAt(i);
                Label end = (Label) exceptionEnds.elementAt(i);
                if (start.getPosition() != end.getPosition()) {
                    code.addExceptionHandler((Label) exceptionStarts.elementAt(i), (Label) exceptionEnds.elementAt(i),
                            handlerStart, throwable);
                }
            }
        }
    }
}
TOP

Related Classes of org.python.compiler.CodeCompiler$ExceptionHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.